// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.core.metadata.ui;

import java.util.ArrayList;
import java.util.List;

import org.dengues.commons.ui.swt.table.AbstractTableViewer;
import org.dengues.core.i18n.Messages;
import org.dengues.core.metadata.MetadataColumn;
import org.dengues.core.metadata.MetadataHelper;
import org.dengues.core.metadata.MetadataTable;
import org.dengues.core.metadata.types.DenguesTypesManager;
import org.dengues.core.metadata.types.MetadataTypesManager;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 */
public class MetadataTableViewer extends AbstractTableViewer {

    private boolean canModifyName = false;

    private final MetadataTable metadataTable;

    public static String PROP_KEY = "PROP_KEY"; //$NON-NLS-1$

    public static String PROP_NAME = "PROP_NAME"; //$NON-NLS-1$

    public static String PROP_DBTYPE = "PROP_DBTYPE"; //$NON-NLS-1$

    public static String PROP_NULLABLE = "PROP_NULLABLE"; //$NON-NLS-1$

    public static String PROP_LENGTH = "PROP_LENGTH"; //$NON-NLS-1$

    public static String PROP_PATTERN = "PROP_PATTERN"; //$NON-NLS-1$

    public static String PROP_PRECISION = "PROP_PRECISION"; //$NON-NLS-1$

    public static String PROP_DEFAULT = "PROP_DEFAULT"; //$NON-NLS-1$

    public static String PROP_COMMENT = "PROP_COMMENT"; //$NON-NLS-1$

    public static String[] BOOLEAN_ITEMS = new String[] { Boolean.FALSE.toString(), Boolean.TRUE.toString() };

    private CellEditor cellEditor;

    private ICellEditorListener editorListener;

    /**
     * Qiang.Zhang.Adolf@gmail.com MetadataTableViewer constructor comment.
     * 
     * @param parent
     * @param style
     */
    public MetadataTableViewer(Composite parent, MetadataTable metadataTable) {
        super(parent);
        this.metadataTable = metadataTable;
        setTitle(Messages.getString("MetadataTableViewer.table", metadataTable.getTableName())); //$NON-NLS-1$
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#addColumns()
     */
    @Override
    public void addColumns() {
        super.addColumns();
        createColumnKey();
        createColumnName();
        createColumnDBType();
        createColumnPattern();
        createColumnNullable();
        createColumnLength();
        createColumnPrecision();
        createColumnDefault();
        createColumnComment();
        // TableColumn[] columns = getTableViewer().getTable().getColumns();
        // for (TableColumn tableColumn : columns) {
        // tableColumn.pack();
        // }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnComment".
     */
    private void createColumnComment() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.comment")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnDefaut".
     */
    private void createColumnDefault() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.default")); //$NON-NLS-1$
        column.setWidth((int) (DEFAULT_COLUMN_WITH * 2.5));
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnPrecision".
     */
    private void createColumnPrecision() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.precision")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnPattern".
     */
    private void createColumnPattern() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.pattern")); //$NON-NLS-1$
        column.setWidth((int) (DEFAULT_COLUMN_WITH * 2.2));
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnLength".
     */
    private void createColumnLength() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.length")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnNullable".
     */
    private void createColumnNullable() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.nullable")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createColumnKey".
     */
    private void createColumnKey() {
        TableColumn column = new TableColumn(table, SWT.CHECK);
        column.setText(Messages.getString("MetadataTableViewer.key")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    private void createColumnDBType() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.dbKey")); //$NON-NLS-1$
        column.setWidth((int) (DEFAULT_COLUMN_WITH * 1.5));
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createNameColumn".
     */
    private void createColumnName() {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(Messages.getString("MetadataTableViewer.name")); //$NON-NLS-1$
        column.setWidth(DEFAULT_COLUMN_WITH);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#attachCellEidtor()
     */
    @Override
    public void attachCellEidtor() {
        String[] props = new String[] { SPACES, PROP_KEY, PROP_NAME, PROP_DBTYPE, PROP_PATTERN, PROP_NULLABLE, PROP_LENGTH,
                PROP_PRECISION, PROP_DEFAULT, PROP_COMMENT };
        tableViewer.setColumnProperties(props);
        List<CellEditor> cells = new ArrayList<CellEditor>();
        for (String prop : props) {
            CellEditor editor = new TextCellEditor(table);
            if (prop.equals(PROP_NULLABLE) || prop.equals(PROP_KEY)) {
                editor = new CheckboxCellEditor(table, SWT.CENTER);
            } else if (prop.equals(PROP_DBTYPE)) {
                editor = new ComboBoxCellEditor(table, MetadataTypesManager.getInstance().getDBTypesLabels(), SWT.READ_ONLY);
            } else if (prop.equals(PROP_PATTERN)) {
                Text control = (Text) editor.getControl();
                installPatternProposal(control);
                control.setEditable(false);
            } else if (prop.equals(PROP_DEFAULT)) {
                installSelectionListener();
            }
            cells.add(editor);
        }
        tableViewer.setCellEditors(cells.toArray(new CellEditor[0]));
    }

    protected void installSelectionListener() {

        final TableEditor tableEditor = new TableEditor(table);
        createEditorListener(tableEditor);
        table.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseDown(MouseEvent e) {
                Point pt = new Point(e.x, e.y);
                TableItem item = table.getItem(pt);
                // deactivate the current cell editor
                if (cellEditor != null && !cellEditor.getControl().isDisposed()) {
                    deactivateCellEditor(tableEditor);
                }
                if (item != null && !item.isDisposed()) {
                    for (int i = 0; i < table.getColumnCount(); i++) {
                        Rectangle rect = item.getBounds(i);
                        if (rect.contains(pt)) {
                            int columnIndex = i;
                            activateCellEditor(item, table, tableEditor, columnIndex);
                        }

                    }
                }
            }
        });
    }

    private ICellEditorListener createEditorListener(final TableEditor tableEditor) {
        editorListener = new ICellEditorListener() {

            public void cancelEditor() {
                deactivateCellEditor(tableEditor);
            }

            public void editorValueChanged(boolean oldValidState, boolean newValidState) {
            }

            public void applyEditorValue() {
            }
        };
        return editorListener;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "activateCellEditor".
     * 
     * @param item
     * @param table
     * @param treeEditor
     * @param columnIndex
     */
    private void activateCellEditor(final TableItem item, final Table table, final TableEditor treeEditor, int columnIndex) {
        // ensure the cell editor is visible
        table.showSelection();

        if (!PROP_DEFAULT.equals(tableViewer.getColumnProperties()[columnIndex])) {
            return;
        }
        MetadataColumn para = (MetadataColumn) item.getData();
        if (para == null || !DenguesTypesManager.DATE.equals(MetadataTypesManager.getJavaTypeFromDBType(para.getType()))) {
            return;
        }

        cellEditor = new DateCellEditorExtended(tableViewer, para);

        if (cellEditor == null) {
            // unable to create the editor
            return;
        }
        // activate the cell editor
        cellEditor.activate();
        // if the cell editor has no control we can stop now
        Control control = cellEditor.getControl();
        if (control == null) {
            cellEditor.deactivate();
            cellEditor = null;
            return;
        }
        // add our editor listener
        cellEditor.addListener(createEditorListener(treeEditor));

        // set the layout of the tree editor to match the cell editor
        CellEditor.LayoutData layout = cellEditor.getLayoutData();
        treeEditor.horizontalAlignment = layout.horizontalAlignment;
        treeEditor.grabHorizontal = layout.grabHorizontal;
        treeEditor.minimumWidth = layout.minimumWidth;
        treeEditor.setEditor(control, item, columnIndex);
        // give focus to the cell editor
        cellEditor.setFocus();

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deactivateCellEditor".
     * 
     * @param tableEditor
     */
    protected void deactivateCellEditor(TableEditor tableEditor) {
        if (cellEditor != null) {
            cellEditor.deactivate();
            cellEditor.removeListener(editorListener);
            cellEditor = null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#attachProvider()
     */
    @Override
    public void attachProvider() {
        MetadataTableViewerProvider provider = new MetadataTableViewerProvider(this);
        tableViewer.setContentProvider(provider);
        tableViewer.setLabelProvider(provider);
        tableViewer.setCellModifier(provider);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#configAddButtonListener()
     */
    @Override
    public SelectionListener configAddButtonListener() {
        return new SelectionAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                MetadataColumn newColumn = MetadataHelper.generateNewColumn(metadataTable);
                List<MetadataColumn> columns = metadataTable.getColumns();
                if (columns == null) {
                    metadataTable.setColumns(new ArrayList<MetadataColumn>());
                }
                columns.add(newColumn);
                getTableViewer().refresh();
            }

        };
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#configRemoveButtonListener()
     */
    @Override
    public SelectionListener configRemoveButtonListener() {
        return new SelectionAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                TableItem[] items = getTableViewer().getTable().getSelection();
                List<MetadataColumn> columns = new ArrayList<MetadataColumn>();
                for (TableItem tableItem : items) {
                    columns.add((MetadataColumn) tableItem.getData());
                }
                metadataTable.getColumns().removeAll(columns);
                getTableViewer().refresh();
            }

        };
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.commons.ui.swt.table.AbstractTableViewer#initTableInput()
     */
    @Override
    public void initTableInput() {
        super.initTableInput();
        tableViewer.setInput(metadataTable);
    }

    public MetadataTable getMetadataTable() {
        return this.metadataTable;
    }

    /**
     * Getter for canModifyName.
     * 
     * @return the canModifyName
     */
    public boolean isCanModifyName() {
        return this.canModifyName;
    }

    /**
     * Sets the canModifyName.
     * 
     * @param canModifyName the canModifyName to set
     */
    public void setCanModifyName(boolean canModifyName) {
        this.canModifyName = canModifyName;
    }

}
